﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using YAXLib;
using RaytracerLib.MathLib;
using RaytracerLib.Attenuations;
using RaytracerLib.Rays;
using RaytracerLib.RenderableObjects;

namespace RaytracerLib.Lights
{
    [DebuggerDisplay("Name: {Name}; Pos: {Pos}, On: {On}")]
    public abstract class Light : OrientedElement
    {
        [YAXNode]
        public ColorFloat Color;

        [YAXNode]
        public bool On = true;

        private Attenuation m_environment_attenuation;

        protected Light(Vector3 a_right, Vector3 a_up)
            : base(a_right, a_up)
        {
        }

        public override bool Remove()
        {
            return Scene.Lights.Remove(this);
        }

        public Attenuation EnvironmentAttenuation
        {
            get
            {
                if (m_environment_attenuation == null)
                {
                    LightTestRay ray = new LightTestRay(Scene, Pos, Vector3.XAXIS);
                    RenderableObject outer_object = Scene.SpatialSubdivisioner.FindOuterObject(ray);
                    if (outer_object != null)
                        m_environment_attenuation = outer_object.DefaultMaterial.Attenuation;
                    else
                        m_environment_attenuation = Scene.RenderOptions.EnvironmentAttenuation;
                }

                return m_environment_attenuation;
            }
        }

        protected override void RenderStart(RenderStartPhase a_phase)
        {
            base.RenderStart(a_phase);

            if (a_phase == RenderStartPhase.RemoveUnusedObjects)
            {
                if (!On)
                    Scene.Lights.Remove(this);
            }
            else if (a_phase == RenderStartPhase.SRGBToLinear)
                Color = Gamma.SRGBToLinear(Color);
        }

        public override string Name
        {
            get
            {
                return base.Name;
            }
            set
            {
                if (Name == value)
                    return;

                if (Scene != null)
                    if (Scene.Lights[value] != null)
                        throw new InvalidOperationException();

                base.Name = value;
            }
        }
    }
}
